import classnames from "classnames";
import { PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Badge } from "../Badge";
import styles from "./index.module.css";
import { Space } from "@/pages/Main/Space";
export interface ToastInfo {
  id?: number | string;
  msg: string;
  duration?: number;
  count?: number;

  badge?: boolean;
  badge_color?: string;
}
interface IToastProps {
  info: ToastInfo;
  onDead: (info: ToastInfo) => void;
}
export function Toast(props: IToastProps) {
  const { info, onDead } = props
  const { msg } = info
  const [dead, setDead] = useState(false)
  const eleRef = useRef<HTMLDivElement>(null)
  const innerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const ele = eleRef.current;
    const inner = innerRef.current;
    if (!ele || !inner) return;
    const { paddingBottom, paddingTop } = getComputedStyle(ele)
    ele.style.height = inner.clientHeight +
      parseInt(paddingBottom) +
      parseInt(paddingTop) + 'px';
    const { duration = 5000 } = info;
    let tid_1 = 0;
    const f = () => {
      setDead(true);
      tid_1 = window.setTimeout(() => onDead(info), 250)
      if (ele) ele.style.height = '0px';
    };
    const tid_0 = window.setTimeout(f, duration);
    return () => {
      window.clearTimeout(tid_0);
      if (tid_1) window.clearTimeout(tid_1)
    }
  }, [info, onDead])

  return (
    <div ref={eleRef} className={classnames(styles.toast, dead && styles.toast_dead)}>
      <Space _ref={innerRef} size='s' className={styles.toast_inner} align='center'>
        {msg}{info.badge !== false && info.count ? <Badge label={info.count} color={info.badge_color} /> : void 0}
      </Space>
    </div>
  )
}

export default function useToast(container = document.body) {
  const ref_new_id = useRef(0);
  const ref_msg_list = useRef<ToastInfo[]>([]);
  const [msg_list, set_msg_list] = useState<ToastInfo[]>([]);

  const toast = useCallback((msg: string | ToastInfo) => {
    const prev_msg_list = ref_msg_list.current;
    let next_msg_list: ToastInfo[];
    if (typeof msg === 'string') {
      const idx = prev_msg_list.findIndex(v => v.msg === msg);
      if (idx < 0) {
        next_msg_list = [{ msg, id: ++ref_new_id.current }, ...prev_msg_list];
      } else {
        const [item] = prev_msg_list.splice(idx, 1);
        const count = (item.count || 0) + 1;
        const new_item: ToastInfo = { ...item, count }
        next_msg_list = [new_item, ...prev_msg_list]
      }
    } else if (msg.id === void 0) {
      next_msg_list = [{ ...msg, id: ++ref_new_id.current }, ...prev_msg_list]
    } else {
      const idx = prev_msg_list.findIndex(i => i.id === msg.id)
      if (idx < 0) {
        next_msg_list = [{ ...msg }, ...prev_msg_list]
      } else {
        next_msg_list = [...prev_msg_list]
        next_msg_list[idx] = { ...msg, count: ((next_msg_list[idx].count || 0) + 1) }
      }
    }
    set_msg_list(ref_msg_list.current = next_msg_list)
  }, [])

  const remove_toast = useCallback((target: ToastInfo) => {
    set_msg_list(ref_msg_list.current = ref_msg_list.current.filter(v => v.id !== target.id))
  }, [])

  const ctx = useMemo(() => {
    if (!msg_list.length) return <></>
    const ele = (
      <div className={styles.toast_list_container}>
        {msg_list.map(v =>
          <Toast key={v.id} info={v} onDead={remove_toast} />
        )}
      </div>
    )
    return container ? createPortal(ele, container) : ele
  }, [container, msg_list, remove_toast])


  const useAuto = useCallback(function useAutoToast(text: any) {
    useEffect(() => { text && toast('' + text) }, [text])
  }, [toast])

  return useMemo(() => [toast, ctx, useAuto] as const, [toast, ctx, useAuto])
}

Toast.show = (msg: string | ToastInfo) => { }
Toast.Provider = function Provider(props: PropsWithChildren) {
  const [toast, toastCtx] = useToast();
  Toast.show = toast;
  return (
    <>
      {toastCtx}
      {props.children}
    </>
  )
}